package com.ass.freedom.net.boot;

import com.ass.freedom.net.handler.ClientHandler;
import com.ass.freedom.net.handler.ClientOps;
import com.ass.freedom.net.handler.decode.FrameDecoder;
import com.ass.freedom.net.handler.decode.FrameToMessageDecoder;
import com.ass.freedom.net.handler.encode.FrameEncoder;
import com.ass.freedom.net.handler.encode.MessageToFrameEncoder;
import com.ass.freedom.net.protocol.FMTraits;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import java.util.concurrent.TimeUnit;


/**
 * Created by syq on 2019/12/31.
 */
public class NettyBootstrapClient {

    private final String HOST = "127.0.0.1";

    private final int PORT = 1884;

    private final String H_FRAME_DECODER = "FrameDecoder";
    private final String H_FRAME_ENCODER = "FrameEncoder";
    private final String H_READ_TIMEOUT = "ReadTimeout";
    private final String H_FM_DECODER = "FMessageDecoder";
    private final String H_FM_ENCODER = "FMessageEncoder";
    private final String H_FM_HANDLER = "FMessagehandler";

    private final int MIN_READ_TIMEOUT = 30;

    private EventLoopGroup bossGroup;

    private EventLoop pingEventLoop;



    public NettyBootstrapClient() {

    }


    public ClientOps start() throws Exception {
        Bootstrap clientBootstrap = new Bootstrap();
        bossGroup = new NioEventLoopGroup();
        pingEventLoop = new DefaultEventLoop();
        clientBootstrap.group(bossGroup)
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        doInitHandler(ch.pipeline());
                    }
                });

        // 启动客户端
        ChannelFuture f = clientBootstrap.connect(HOST, PORT);
        Channel ch = f.channel();

        ClientOps ops = new ClientOps(ch, pingEventLoop);
        ch.attr(ClientHandler.CLIENT).set(ops);
        f.sync();
        // 等待连接关闭
        return ops;
    }


    public void close() throws Exception {
        if (bossGroup != null) {
            bossGroup.shutdownGracefully();
        }
        if (pingEventLoop != null) {
            pingEventLoop.shutdownGracefully();
        }
    }



    private void doInitHandler(ChannelPipeline channelPipeline) {

        FrameToMessageDecoder frameToMessageDecoder = new FrameToMessageDecoder();
        MessageToFrameEncoder messageToFrameEncoder = new MessageToFrameEncoder();
        frameToMessageDecoder.addFMessageTrait(FMTraits.FMTBytes);
        messageToFrameEncoder.addFMessageTrait(FMTraits.FMTBytes);

        frameToMessageDecoder.addFMessageTrait(FMTraits.FMTString);
        messageToFrameEncoder.addFMessageTrait(FMTraits.FMTString);

        frameToMessageDecoder.addFMessageTrait(FMTraits.FMTJson);
        messageToFrameEncoder.addFMessageTrait(FMTraits.FMTJson);

        channelPipeline.addLast(H_FRAME_DECODER, new FrameDecoder());
        channelPipeline.addLast(H_FRAME_ENCODER, new FrameEncoder());

        channelPipeline.addLast(H_READ_TIMEOUT, new ReadTimeoutHandler(MIN_READ_TIMEOUT, TimeUnit.SECONDS));

        channelPipeline.addLast(H_FM_DECODER, frameToMessageDecoder);
        channelPipeline.addLast(H_FM_ENCODER,  messageToFrameEncoder);

        channelPipeline.addLast(H_FM_HANDLER, new ClientHandler(pingEventLoop));
    }
}
